// ----------------------------------------------------------------------------
// memory_barrier.h
// ----------------------------------------------------------------------------
/*
 Description:
 CPUメモリバリア.
 ----------------------------------------------------------------
 使い方.
 メモリバリアを明示的に宣言したい場合に利用する.
 
 基本的にはメモリへの書き込み操作を行った場合はWriteバリアを後に配置し、
 メモリへの読み込み操作を行う場合はReadバリアを前に配置します.
 
 バリア自体は命令のリオーダーを抑制する概念であり、
 通常のメモリ書き込みはアトミックではないことに注意.
 アトミックな値の操作を行いたい場合はatomic命令
 (atomic_counter.h, atomic_intrinsic.h)を使います.
 
 see also. http://ja.wikipedia.org/wiki/メモリバリア
 
 */
#pragma once
#include <fw/base/core/macros.h>

#if USING(FW_COMPILER_MSC) || USING(FW_COMPILER_MSVC)
	// MSVC.
	#include <math.h>
	#include <intrin.h>
	extern "C" void _ReadBarrier();
	extern "C" void _WriteBarrier();
	extern "C" void _ReadWriteBarrier();
	#pragma intrinsic(_ReadBarrier)
	#pragma intrinsic(_WriteBarrier)
	#pragma intrinsic(_ReadWriteBarrier)
	#define _MemoryBarrier()	_mm_mfence()
#elif USING(FW_COMPILER_GCC) || USING(FW_COMPILER_CLANG)
	// gcc/clang.
	#define _ReadBarrier()		asm volatile("":::"memory")
	#define _WriteBarrier()		asm volatile("":::"memory")
	#define _ReadWriteBarrier()	asm volatile("":::"memory")
	#define _MemoryBarrier()	__sync_synchronize()
#else
#error "This compiler is not supported yet."
#endif

namespace fw
{
	FW_FORCE_INLINE void FW_READ_BARRIER()
	{
		_ReadBarrier();
	}
	
	FW_FORCE_INLINE void FW_WRITE_BARRIER()
	{
		_WriteBarrier();
	}
	
	FW_FORCE_INLINE void FW_READ_WRITE_BARRIER()
	{
		_ReadWriteBarrier();
	}
	
	FW_FORCE_INLINE void FW_MEMORY_BARRIER()
	{
		_MemoryBarrier();
	}
	
} // namespace fw
